// Copyright (c) Microsoft Corporation.  All Rights Reserved.  See License.txt in the project root for license information.

namespace Microsoft.FSharp.Collections

    open System
    open System.Collections.Generic
    open Microsoft.FSharp.Core
    open Microsoft.FSharp.Collections

    /// <summary>Basic operations on lists.</summary>
    [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
    [<RequireQualifiedAccess>]
    module List = 

        /// <summary>Returns a new list that contains the cartesian product of the two input lists.</summary>
        /// <param name="list1">The first input list.</param>
        /// <param name="list2">The second input list.</param>
        /// <returns>The resulting list of pairs.</returns>
        [<CompiledName("AllPairs")>]
        val allPairs: list1:'T1 list -> list2:'T2 list -> ('T1 * 'T2) list

        /// <summary>Returns a new list that contains the elements of the first list
        /// followed by elements of the second.</summary>
        /// <param name="list1">The first input list.</param>
        /// <param name="list2">The second input list.</param>
        /// <returns>The resulting list.</returns>
        [<CompiledName("Append")>]
        val append: list1:'T list -> list2:'T list -> 'T list

        /// <summary>Returns the average of the elements in the list.</summary>
        ///
        /// <remarks>Raises <c>System.ArgumentException</c> if <c>list</c> is empty.</remarks>
        /// <param name="list">The input list.</param>
        /// <exception cref="System.ArgumentException">Thrown when the list is empty.</exception>
        /// <returns>The resulting average.</returns>
        [<CompiledName("Average")>]
        val inline average   : list:^T list -> ^T    
                                   when ^T : (static member ( + ) : ^T * ^T -> ^T) 
                                   and  ^T : (static member DivideByInt : ^T*int -> ^T) 
                                   and  ^T : (static member Zero : ^T)

        /// <summary>Returns the average of the elements generated by applying the function to each element of the list.</summary>
        ///
        /// <remarks>Raises <c>System.ArgumentException</c> if <c>list</c> is empty.</remarks>
        /// <param name="projection">The function to transform the list elements into the type to be averaged.</param>
        /// <param name="list">The input list.</param>
        /// <exception cref="System.ArgumentException">Thrown when the list is empty.</exception>
        /// <returns>The resulting average.</returns>
        [<CompiledName("AverageBy")>]
        val inline averageBy   : projection:('T -> ^U) -> list:'T list  -> ^U    
                                   when ^U : (static member ( + ) : ^U * ^U -> ^U) 
                                   and  ^U : (static member DivideByInt : ^U*int -> ^U) 
                                   and  ^U : (static member Zero : ^U)

        /// <summary>Applies the given function to each element of the list. Returns
        /// the list comprised of the results <c>x</c> for each element where
        /// the function returns Some(x)</summary>
        /// <param name="chooser">The function to generate options from the elements.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The list comprising the values selected from the chooser function.</returns>
        [<CompiledName("Choose")>]
        val choose: chooser:('T -> 'U option) -> list:'T list -> 'U list

        /// <summary>Divides the input list into chunks of size at most <c>chunkSize</c>.</summary>
        /// <param name="chunkSize">The maximum size of each chunk.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The list divided into chunks.</returns>
        /// <exception cref="System.ArgumentException">Thrown when <c>chunkSize</c> is not positive.</exception>
        [<CompiledName("ChunkBySize")>]
        val chunkBySize: chunkSize:int -> list:'T list -> 'T list list

        /// <summary>For each element of the list, applies the given function. Concatenates all the results and return the combined list.</summary>
        /// <param name="mapping">The function to transform each input element into a sublist to be concatenated.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The concatenation of the transformed sublists.</returns>
        [<CompiledName("Collect")>]
        val collect: mapping:('T -> 'U list) -> list:'T list -> 'U list

        /// <summary>Compares two lists using the given comparison function, element by element.</summary>
        ///
        /// <param name="comparer">A function that takes an element from each list and returns an int.
        /// If it evaluates to a non-zero value iteration is stopped and that value is returned.</param>
        /// <param name="list1">The first input list.</param>
        /// <param name="list2">The second input list.</param>
        ///
        /// <returns>Returns the first non-zero result from the comparison function. If the first list has a 
        /// larger element, the return value is always positive. If the second list has a larger 
        /// element, the return value is always negative. When the elements are equal in the two 
        /// lists, 1 is returned if the first list is longer, 0 is returned if they are equal in 
        /// length, and -1 is returned when the second list is longer.</returns>
        [<CompiledName("CompareWith")>]
        val inline compareWith: comparer:('T -> 'T -> int) -> list1:'T list -> list2:'T list -> int

        /// <summary>Returns a new list that contains the elements of each the lists in order.</summary>
        /// <param name="lists">The input sequence of lists.</param>
        /// <returns>The resulting concatenated list.</returns>
        [<CompiledName("Concat")>]
        val concat: lists:seq<'T list> -> 'T list
        
        /// <summary>Tests if the list contains the specified element.</summary>
        /// <param name="value">The value to locate in the input list.</param>
        /// <param name="source">The input list.</param>
        /// <returns>True if the input list contains the specified element; false otherwise.</returns>
        [<CompiledName("Contains")>]
        val inline contains: value:'T -> source:'T list -> bool when 'T : equality

        /// <summary>Returns a list that contains no duplicate entries according to generic hash and
        /// equality comparisons on the entries.
        /// If an element occurs multiple times in the list then the later occurrences are discarded.</summary>
        ///
        /// <param name="list">The input list.</param>
        ///
        /// <returns>The result list.</returns>
        [<CompiledName("Distinct")>]
        val distinct: list:'T list -> 'T list when 'T : equality

        /// <summary>Returns a list that contains no duplicate entries according to the 
        /// generic hash and equality comparisons on the keys returned by the given key-generating function.
        /// If an element occurs multiple times in the list then the later occurrences are discarded.</summary>
        ///
        /// <param name="projection">A function transforming the list items into comparable keys.</param>
        /// <param name="list">The input list.</param>
        ///
        /// <returns>The result list.</returns>
        [<CompiledName("DistinctBy")>]
        val distinctBy: projection:('T -> 'Key) -> list:'T list -> 'T list when 'Key : equality

        /// <summary>Applies a key-generating function to each element of a list and returns a list yielding unique
        /// keys and their number of occurrences in the original list.</summary>
        ///
        /// <param name="projection">A function transforming each item of the input list into a key to be
        /// compared against the others.</param>
        /// <param name="list">The input list.</param>
        ///
        /// <returns>The result list.</returns>
        [<CompiledName("CountBy")>]
        val countBy : projection:('T -> 'Key) -> list:'T list -> ('Key * int) list when 'Key : equality

        /// <summary>Splits the input list into at most <c>count</c> chunks.</summary>
        /// <param name="count">The maximum number of chunks.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The list split into chunks.</returns>
        /// <exception cref="System.ArgumentException">Thrown when <c>count</c> is not positive.</exception>
        [<CompiledName("SplitInto")>]
        val splitInto: count:int -> list:'T list -> 'T list list

        /// <summary>Returns an empty list of the given type.</summary>
        [<GeneralizableValue>]
        [<CompiledName("Empty")>]
        val empty<'T> : 'T list

        /// <summary>Returns a new list with the distinct elements of the input list which do not appear in the itemsToExclude sequence,
        /// using generic hash and equality comparisons to compare values.</summary>
        ///
        /// <param name="itemsToExclude">A sequence whose elements that also occur in the input list will cause those elements to be
        /// removed from the result.</param>
        /// <param name="list">A list whose elements that are not also in itemsToExclude will be returned.</param>
        ///
        /// <returns>A list that contains the distinct elements of <c>list</c> that do not appear in <c>itemsToExclude</c>.</returns>
        ///
        /// <exception cref="System.ArgumentNullException">Thrown when itemsToExclude is null.</exception>
        [<CompiledName("Except")>]
        val except: itemsToExclude:seq<'T> -> list:'T list -> 'T list when 'T : equality

        /// <summary>Returns the only element of the list.</summary>
        ///
        /// <param name="list">The input list.</param>
        ///
        /// <returns>The only element of the list.</returns>
        ///        
        /// <exception cref="System.ArgumentException">Thrown when the input does not have precisely one element.</exception>
        [<CompiledName("ExactlyOne")>]
        val exactlyOne: list:'T list -> 'T

        /// <summary>Tests if any element of the list satisfies the given predicate.</summary>
        ///
        /// <remarks>The predicate is applied to the elements of the input list. If any application 
        /// returns true then the overall result is true and no further elements are tested. 
        /// Otherwise, false is returned.</remarks>
        /// <param name="predicate">The function to test the input elements.</param>
        /// <param name="list">The input list.</param>
        /// <returns>True if any element satisfies the predicate.</returns>
        [<CompiledName("Exists")>]
        val exists: predicate:('T -> bool) -> list:'T list -> bool

        /// <summary>Tests if any pair of corresponding elements of the lists satisfies the given predicate.</summary>
        ///
        /// <remarks>The predicate is applied to matching elements in the two collections up to the lesser of the 
        /// two lengths of the collections. If any application returns true then the overall result is 
        /// true and no further elements are tested. Otherwise, if one collections is longer 
        /// than the other then the <c>System.ArgumentException</c> exception is raised. 
        /// Otherwise, false is returned.</remarks>
        /// <param name="predicate">The function to test the input elements.</param>
        /// <param name="list1">The first input list.</param>
        /// <param name="list2">The second input list.</param>
        /// <exception cref="System.ArgumentException">Thrown when the input lists differ in length.</exception>
        /// <returns>True if any pair of elements satisfy the predicate.</returns>
        [<CompiledName("Exists2")>]
        val exists2: predicate:('T1 -> 'T2 -> bool) -> list1:'T1 list -> list2:'T2 list -> bool

        /// <summary>Returns the first element for which the given function returns True.
        /// Raises <c>KeyNotFoundException</c> if no such element exists.</summary>
        /// <param name="predicate">The function to test the input elements.</param>
        /// <param name="list">The input list.</param>
        /// <exception cref="System.Collections.Generic.KeyNotFoundException">Thrown if the predicate evaluates to false for
        /// all the elements of the list.</exception>
        /// <returns>The first element that satisfies the predicate.</returns>
        [<CompiledName("Find")>]
        val find: predicate:('T -> bool) -> list:'T list -> 'T

        /// <summary>Returns the last element for which the given function returns True.
        /// Raises <c>KeyNotFoundException</c> if no such element exists.</summary>
        /// <param name="predicate">The function to test the input elements.</param>
        /// <param name="list">The input list.</param>
        /// <exception cref="System.Collections.Generic.KeyNotFoundException">Thrown if the predicate evaluates to false for
        /// all the elements of the list.</exception>
        /// <returns>The last element that satisfies the predicate.</returns>
        [<CompiledName("FindBack")>]
        val findBack: predicate:('T -> bool) -> list:'T list -> 'T

        /// <summary>Returns the index of the first element in the list
        /// that satisfies the given predicate.
        /// Raises <c>KeyNotFoundException</c> if no such element exists.</summary>
        /// <param name="predicate">The function to test the input elements.</param>
        /// <param name="list">The input list.</param>
        /// <exception cref="System.ArgumentException">Thrown if the predicate evaluates to false for all the
        /// elements of the list.</exception>
        /// <returns>The index of the first element that satisfies the predicate.</returns>
        [<CompiledName("FindIndex")>]
        val findIndex: predicate:('T -> bool) -> list:'T list -> int

        /// <summary>Returns the index of the last element in the list
        /// that satisfies the given predicate.
        /// Raises <c>KeyNotFoundException</c> if no such element exists.</summary>
        /// <param name="predicate">The function to test the input elements.</param>
        /// <param name="list">The input list.</param>
        /// <exception cref="System.ArgumentException">Thrown if the predicate evaluates to false for all the
        /// elements of the list.</exception>
        /// <returns>The index of the last element that satisfies the predicate.</returns>
        [<CompiledName("FindIndexBack")>]
        val findIndexBack: predicate:('T -> bool) -> list:'T list -> int

        /// <summary>Returns a new collection containing only the elements of the collection
        /// for which the given predicate returns "true"</summary>
        /// <param name="predicate">The function to test the input elements.</param>
        /// <param name="list">The input list.</param>
        /// <returns>A list containing only the elements that satisfy the predicate.</returns>
        [<CompiledName("Filter")>]
        val filter: predicate:('T -> bool) -> list:'T list -> 'T list

        /// <summary>Applies a function to each element of the collection, threading an accumulator argument
        /// through the computation. Take the second argument, and apply the function to it
        /// and the first element of the list. Then feed this result into the function along
        /// with the second element and so on. Return the final result.
        /// If the input function is <c>f</c> and the elements are <c>i0...iN</c> then 
        /// computes <c>f (... (f s i0) i1 ...) iN</c>.</summary>
        /// <param name="folder">The function to update the state given the input elements.</param>
        /// <param name="state">The initial state.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The final state value.</returns>
        [<CompiledName("Fold")>]
        val fold<'T,'State> : folder:('State -> 'T -> 'State) -> state:'State -> list:'T list -> 'State

        /// <summary>Applies a function to corresponding elements of two collections, threading an accumulator argument
        /// through the computation. The collections must have identical sizes.
        /// If the input function is <c>f</c> and the elements are <c>i0...iN</c> and <c>j0...jN</c>
        /// then computes <c>f (... (f s i0 j0)...) iN jN</c>.</summary>
        /// <param name="folder">The function to update the state given the input elements.</param>
        /// <param name="state">The initial state.</param>
        /// <param name="list1">The first input list.</param>
        /// <param name="list2">The second input list.</param>
        /// <returns>The final state value.</returns>
        [<CompiledName("Fold2")>]
        val fold2<'T1,'T2,'State> : folder:('State -> 'T1 -> 'T2 -> 'State) -> state:'State -> list1:'T1 list -> list2:'T2 list -> 'State

        /// <summary>Applies a function to each element of the collection, starting from the end, threading an accumulator argument
        /// through the computation. If the input function is <c>f</c> and the elements are <c>i0...iN</c> then 
        /// computes <c>f i0 (...(f iN s))</c>.</summary>
        /// <param name="folder">The function to update the state given the input elements.</param>
        /// <param name="list">The input list.</param>
        /// <param name="state">The initial state.</param>
        /// <returns>The state object after the folding function is applied to each element of the list.</returns>
        [<CompiledName("FoldBack")>]
        val foldBack<'T,'State> : folder:('T -> 'State -> 'State) -> list:'T list -> state:'State -> 'State

        /// <summary>Applies a function to corresponding elements of two collections, threading an accumulator argument
        /// through the computation. The collections must have identical sizes.
        /// If the input function is <c>f</c> and the elements are <c>i0...iN</c> and <c>j0...jN</c>
        /// then computes <c>f i0 j0 (...(f iN jN s))</c>.</summary>
        /// <param name="folder">The function to update the state given the input elements.</param>
        /// <param name="list1">The first input list.</param>
        /// <param name="list2">The second input list.</param>
        /// <param name="state">The initial state.</param>
        /// <returns>The final state value.</returns>
        [<CompiledName("FoldBack2")>]
        val foldBack2<'T1,'T2,'State> : folder:('T1 -> 'T2 -> 'State -> 'State) -> list1:'T1 list -> list2:'T2 list -> state:'State -> 'State

        /// <summary>Tests if all elements of the collection satisfy the given predicate.</summary>
        ///
        /// <remarks>The predicate is applied to the elements of the input list. If any application 
        /// returns false then the overall result is false and no further elements are tested. 
        /// Otherwise, true is returned.</remarks>
        /// <param name="predicate">The function to test the input elements.</param>
        /// <param name="list">The input list.</param>
        /// <returns>True if all of the elements satisfy the predicate.</returns>
        [<CompiledName("ForAll")>]
        val forall: predicate:('T -> bool) -> list:'T list -> bool

        /// <summary>Tests if all corresponding elements of the collection satisfy the given predicate pairwise.</summary>
        ///
        /// <remarks>The predicate is applied to matching elements in the two collections up to the lesser of the 
        /// two lengths of the collections. If any application returns false then the overall result is 
        /// false and no further elements are tested. Otherwise, if one collection is longer 
        /// than the other then the <c>System.ArgumentException</c> exception is raised. 
        /// Otherwise, true is returned.</remarks>
        /// <param name="predicate">The function to test the input elements.</param>
        /// <param name="list1">The first input list.</param>
        /// <param name="list2">The second input list.</param>
        /// <exception cref="System.ArgumentException">Thrown when the input lists differ in length.</exception>
        /// <returns>True if all of the pairs of elements satisfy the predicate.</returns>
        [<CompiledName("ForAll2")>]
        val forall2: predicate:('T1 -> 'T2 -> bool) -> list1:'T1 list -> list2:'T2 list -> bool

        /// <summary>Applies a key-generating function to each element of a list and yields a list of 
        /// unique keys. Each unique key contains a list of all elements that match 
        /// to this key.</summary>
        ///
        /// <param name="projection">A function that transforms an element of the list into a comparable key.</param>
        /// <param name="list">The input list.</param>
        ///
        /// <returns>The result list.</returns>
        [<CompiledName("GroupBy")>]
        val groupBy : projection:('T -> 'Key) -> list:'T list -> ('Key * 'T list) list when 'Key : equality

        /// <summary>Returns the first element of the list.</summary>
        ///
        /// <param name="list">The input list.</param>
        /// <exception cref="System.ArgumentException">Thrown when the list is empty.</exception>
        /// <returns>The first element of the list.</returns>
        [<CompiledName("Head")>]
        val head: list:'T list -> 'T

        /// <summary>Returns a new list whose elements are the corresponding elements
        /// of the input list paired with the index (from 0) of each element.</summary>
        /// <param name="list">The input list.</param>
        /// <returns>The list of indexed elements.</returns>
        [<CompiledName("Indexed")>]
        val indexed: list:'T list -> (int * 'T) list

        /// <summary>Creates a list by calling the given generator on each index.</summary>
        /// <param name="length">The length of the list to generate.</param>
        /// <param name="initializer">The function to generate an element from an index.</param>
        /// <returns>The list of generated elements.</returns>
        [<CompiledName("Initialize")>]
        val init: length:int -> initializer:(int -> 'T) -> 'T list

        /// <summary>Returns true if the list contains no elements, false otherwise.</summary>
        /// <param name="list">The input list.</param>
        /// <returns>True if the list is empty.</returns>
        [<CompiledName("IsEmpty")>]
        val isEmpty: list:'T list -> bool

        /// <summary>Indexes into the list. The first element has index 0.</summary>
        /// <param name="index">The index to retrieve.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The value at the given index.</returns>
        /// <exception cref="System.ArgumentException">Thrown when the index is negative or the input list does not contain enough elements.</exception>
        [<CompiledName("Item")>]
        val item: index:int -> list:'T list -> 'T

        /// <summary>Applies the given function to each element of the collection.</summary>
        /// <param name="action">The function to apply to elements from the input list.</param>
        /// <param name="list">The input list.</param>
        [<CompiledName("Iterate")>]
        val iter: action:('T -> unit) -> list:'T list -> unit

        /// <summary>Applies the given function to two collections simultaneously. The
        /// collections must have identical size.</summary>
        /// <param name="action">The function to apply to pairs of elements from the input lists.</param>
        /// <param name="list1">The first input list.</param>
        /// <param name="list2">The second input list.</param>
        [<CompiledName("Iterate2")>]
        val iter2: action:('T1 -> 'T2 -> unit) -> list1:'T1 list -> list2:'T2 list -> unit

        /// <summary>Applies the given function to each element of the collection. The integer passed to the
        /// function indicates the index of element.</summary>
        /// <param name="action">The function to apply to the elements of the list along with their index.</param>
        /// <param name="list">The input list.</param>
        [<CompiledName("IterateIndexed")>]
        val iteri: action:(int -> 'T -> unit) -> list:'T list -> unit

        /// <summary>Applies the given function to two collections simultaneously. The
        /// collections must have identical size. The integer passed to the
        /// function indicates the index of element.</summary>
        /// <param name="action">The function to apply to a pair of elements from the input lists along with their index.</param>
        /// <param name="list1">The first input list.</param>
        /// <param name="list2">The second input list.</param>
        [<CompiledName("IterateIndexed2")>]
        val iteri2: action:(int -> 'T1 -> 'T2 -> unit) -> list1:'T1 list -> list2:'T2 list -> unit

        /// <summary>Returns the last element of the list.</summary>
        /// <param name="list">The input list.</param>
        /// <returns>The last element of the list.</returns>
        /// <exception cref="System.ArgumentException">Thrown when the input does not have any elements.</exception>
        [<CompiledName("Last")>]
        val last: list:'T list -> 'T

        /// <summary>Returns the length of the list.</summary>
        /// <param name="list">The input list.</param>
        /// <returns>The length of the list.</returns>
        [<CompiledName("Length")>]
        val length: list:'T list -> int

        /// <summary>Returns the last element of the list.
        /// Return <c>None</c> if no such element exists.</summary>
        /// <param name="list">The input list.</param>
        /// <returns>The last element of the list or None.</returns>
        [<CompiledName("TryLast")>]
        val tryLast: list:'T list -> 'T option

        /// <summary>Builds a new collection whose elements are the results of applying the given function
        /// to each of the elements of the collection.</summary>
        /// <param name="mapping">The function to transform elements from the input list.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The list of transformed elements.</returns>
        [<CompiledName("Map")>]
        val map: mapping:('T -> 'U) -> list:'T list -> 'U list

        /// <summary>Builds a new collection whose elements are the results of applying the given function
        /// to the corresponding elements of the two collections pairwise.</summary>
        /// <param name="mapping">The function to transform pairs of elements from the input lists.</param>
        /// <param name="list1">The first input list.</param>
        /// <param name="list2">The second input list.</param>
        /// <returns>The list of transformed elements.</returns>
        [<CompiledName("Map2")>]
        val map2: mapping:('T1 -> 'T2 -> 'U) -> list1:'T1 list -> list2:'T2 list -> 'U list

        /// <summary>Builds a new collection whose elements are the results of applying the given function
        /// to the corresponding elements of the three collections simultaneously.</summary>
        /// <param name="mapping">The function to transform triples of elements from the input lists.</param>
        /// <param name="list1">The first input list.</param>
        /// <param name="list2">The second input list.</param>
        /// <param name="list3">The third input list.</param>
        /// <returns>The list of transformed elements.</returns>
        [<CompiledName("Map3")>]
        val map3: mapping:('T1 -> 'T2 -> 'T3 -> 'U) -> list1:'T1 list -> list2:'T2 list -> list3:'T3 list -> 'U list

        /// <summary>Combines map and fold. Builds a new list whose elements are the results of applying the given function
        /// to each of the elements of the input list. The function is also used to accumulate a final value.</summary>
        /// <param name="mapping">The function to transform elements from the input list and accumulate the final value.</param>
        /// <param name="state">The initial state.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The list of transformed elements, and the final accumulated value.</returns>
        [<CompiledName("MapFold")>]
        val mapFold<'T,'State,'Result> : mapping:('State -> 'T -> 'Result * 'State) -> state:'State -> list:'T list -> 'Result list * 'State

        /// <summary>Combines map and foldBack. Builds a new list whose elements are the results of applying the given function
        /// to each of the elements of the input list. The function is also used to accumulate a final value.</summary>
        /// <param name="mapping">The function to transform elements from the input list and accumulate the final value.</param>
        /// <param name="list">The input list.</param>
        /// <param name="state">The initial state.</param>
        /// <returns>The list of transformed elements, and the final accumulated value.</returns>
        [<CompiledName("MapFoldBack")>]
        val mapFoldBack<'T,'State,'Result> : mapping:('T -> 'State -> 'Result * 'State) -> list:'T list -> state:'State -> 'Result list * 'State

        /// <summary>Builds a new collection whose elements are the results of applying the given function
        /// to each of the elements of the collection. The integer index passed to the
        /// function indicates the index (from 0) of element being transformed.</summary>
        /// <param name="mapping">The function to transform elements and their indices.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The list of transformed elements.</returns>
        [<CompiledName("MapIndexed")>]
        val mapi: mapping:(int -> 'T -> 'U) -> list:'T list -> 'U list

        /// <summary>Like mapi, but mapping corresponding elements from two lists of equal length.</summary>
        /// <param name="mapping">The function to transform pairs of elements from the two lists and their index.</param>
        /// <param name="list1">The first input list.</param>
        /// <param name="list2">The second input list.</param>
        /// <returns>The list of transformed elements.</returns>
        [<CompiledName("MapIndexed2")>]
        val mapi2: mapping:(int -> 'T1 -> 'T2 -> 'U) -> list1:'T1 list -> list2:'T2 list -> 'U list

        /// <summary>Return the greatest of all elements of the list, compared via Operators.max.</summary>
        ///
        /// <remarks>Raises <c>System.ArgumentException</c> if <c>list</c> is empty</remarks>
        /// <param name="list">The input list.</param>
        /// <exception cref="System.ArgumentException">Thrown when the list is empty.</exception>
        /// <returns>The maximum element.</returns>
        [<CompiledName("Max")>]
        val inline max     : list:'T list -> 'T when 'T : comparison 

        /// <summary>Returns the greatest of all elements of the list, compared via Operators.max on the function result.</summary>
        ///
        /// <remarks>Raises <c>System.ArgumentException</c> if <c>list</c> is empty.</remarks>
        /// <param name="projection">The function to transform the list elements into the type to be compared.</param>
        /// <param name="list">The input list.</param>
        /// <exception cref="System.ArgumentException">Thrown when the list is empty.</exception>
        /// <returns>The maximum element.</returns>
        [<CompiledName("MaxBy")>]
        val inline maxBy   : projection:('T -> 'U) -> list:'T list -> 'T when 'U : comparison 

        /// <summary>Returns the lowest of all elements of the list, compared via Operators.min.</summary>
        ///
        /// <remarks>Raises <c>System.ArgumentException</c> if <c>list</c> is empty</remarks>
        /// <param name="list">The input list.</param>
        /// <exception cref="System.ArgumentException">Thrown when the list is empty.</exception>
        /// <returns>The minimum value.</returns>
        [<CompiledName("Min")>]
        val inline min     : list:'T list -> 'T when 'T : comparison 

        /// <summary>Returns the lowest of all elements of the list, compared via Operators.min on the function result</summary>
        ///
        /// <remarks>Raises <c>System.ArgumentException</c> if <c>list</c> is empty.</remarks>
        /// <param name="projection">The function to transform list elements into the type to be compared.</param>
        /// <param name="list">The input list.</param>
        /// <exception cref="System.ArgumentException">Thrown when the list is empty.</exception>
        /// <returns>The minimum value.</returns>
        [<CompiledName("MinBy")>]
        val inline minBy   : projection:('T -> 'U) -> list:'T list -> 'T when 'U : comparison 

        /// <summary>Indexes into the list. The first element has index 0.</summary>
        /// <param name="list">The input list.</param>
        /// <param name="index">The index to retrieve.</param>
        /// <returns>The value at the given index.</returns>
        /// <exception cref="System.ArgumentException">Thrown when the index is negative or the input list does not contain enough elements.</exception>
        [<CompiledName("Get")>]
        [<Obsolete("please use List.item")>]
        val nth: list:'T list -> index:int -> 'T

        /// <summary>Builds a list from the given array.</summary>
        /// <param name="array">The input array.</param>
        /// <returns>The list of elements from the array.</returns>
        [<CompiledName("OfArray")>]
        val ofArray : array:'T[] -> 'T list

        /// <summary>Builds a new list from the given enumerable object.</summary>
        /// <param name="source">The input sequence.</param>
        /// <returns>The list of elements from the sequence.</returns>
        [<CompiledName("OfSeq")>]
        val ofSeq: source:seq<'T> -> 'T list

        /// <summary>Returns a list of each element in the input list and its predecessor, with the
        /// exception of the first element which is only returned as the predecessor of the second element.</summary>
        ///
        /// <param name="list">The input list.</param>
        ///
        /// <returns>The result list.</returns>
        [<CompiledName("Pairwise")>]
        val pairwise: list:'T list -> ('T * 'T) list

        /// <summary>Splits the collection into two collections, containing the 
        /// elements for which the given predicate returns True and False
        /// respectively. Element order is preserved in both of the created lists.</summary>
        /// <param name="predicate">The function to test the input elements.</param>
        /// <param name="list">The input list.</param>
        /// <returns>A list containing the elements for which the predicate evaluated to false and a list
        /// containing the elements for which the predicate evaluated to true.</returns>
        [<CompiledName("Partition")>]
        val partition: predicate:('T -> bool) -> list:'T list -> ('T list * 'T list)

        /// <summary>Applies the given function to successive elements, returning the first
        /// result where function returns <c>Some(x)</c> for some x. If no such
        /// element exists then raise <c>System.Collections.Generic.KeyNotFoundException</c></summary>
        /// <param name="chooser">The function to generate options from the elements.</param>
        /// <param name="list">The input list.</param>
        /// <exception cref="System.Collections.Generic.KeyNotFoundException">Thrown when the list is empty.</exception>
        /// <returns>The first resulting value.</returns>
        [<CompiledName("Pick")>]
        val pick: chooser:('T -> 'U option) -> list:'T list -> 'U

        /// <summary>Returns a list with all elements permuted according to the
        /// specified permutation.</summary>
        /// <param name="indexMap">The function to map input indices to output indices.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The permuted list.</returns>
        /// <exception cref="System.ArgumentException">Thrown when indexMap does not produce a valid permutation.</exception>
        [<CompiledName("Permute")>]
        val permute : indexMap:(int -> int) -> list:'T list -> 'T list

        /// <summary>Apply a function to each element of the collection, threading an accumulator argument
        /// through the computation. Apply the function to the first two elements of the list.
        /// Then feed this result into the function along with the third element and so on. 
        /// Return the final result. If the input function is <c>f</c> and the elements are <c>i0...iN</c> then computes 
        /// <c>f (... (f i0 i1) i2 ...) iN</c>.</summary>
        ///
        /// <remarks>Raises <c>System.ArgumentException</c> if <c>list</c> is empty</remarks>
        /// <param name="reduction">The function to reduce two list elements to a single element.</param>
        /// <param name="list">The input list.</param>
        /// <exception cref="System.ArgumentException">Thrown when the list is empty.</exception>
        /// <returns>The final reduced value.</returns>
        [<CompiledName("Reduce")>]
        val reduce: reduction:('T -> 'T -> 'T) -> list:'T list -> 'T

        /// <summary>Applies a function to each element of the collection, starting from the end, threading an accumulator argument
        /// through the computation. If the input function is <c>f</c> and the elements are <c>i0...iN</c> then computes 
        /// <c>f i0 (...(f iN-1 iN))</c>.</summary>
        /// <param name="reduction">A function that takes in the next-to-last element of the list and the
        /// current accumulated result to produce the next accumulated result.</param>
        /// <param name="list">The input list.</param>
        /// <exception cref="System.ArgumentException">Thrown when the list is empty.</exception>
        /// <returns>The final result of the reductions.</returns>
        [<CompiledName("ReduceBack")>]
        val reduceBack: reduction:('T -> 'T -> 'T) -> list:'T list -> 'T

        /// <summary>Creates a list by replicating the given initial value.</summary>
        /// <param name="count">The number of elements to replicate.</param>
        /// <param name="initial">The value to replicate</param>
        /// <returns>The generated list.</returns>
        [<CompiledName("Replicate")>]
        val replicate: count:int -> initial:'T -> 'T list

        /// <summary>Returns a new list with the elements in reverse order.</summary>
        /// <param name="list">The input list.</param>
        /// <returns>The reversed list.</returns>
        [<CompiledName("Reverse")>]
        val rev: list:'T list -> 'T list

        /// <summary>Applies a function to each element of the collection, threading an accumulator argument
        /// through the computation. Take the second argument, and apply the function to it
        /// and the first element of the list. Then feed this result into the function along
        /// with the second element and so on. Returns the list of intermediate results and the final result.</summary>
        /// <param name="folder">The function to update the state given the input elements.</param>
        /// <param name="state">The initial state.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The list of states.</returns>
        [<CompiledName("Scan")>]
        val scan<'T,'State>  : folder:('State -> 'T -> 'State) -> state:'State -> list:'T list -> 'State list

        /// <summary>Like <c>foldBack</c>, but returns both the intermediary and final results</summary>
        /// <param name="folder">The function to update the state given the input elements.</param>
        /// <param name="list">The input list.</param>
        /// <param name="state">The initial state.</param>
        /// <returns>The list of states.</returns>
        [<CompiledName("ScanBack")>]
        val scanBack<'T,'State> : folder:('T -> 'State -> 'State) -> list:'T list -> state:'State -> 'State list

        /// <summary>Returns a list that contains one item only.</summary>
        ///
        /// <param name="value">The input item.</param>
        ///
        /// <returns>The result list of one item.</returns>
        [<CompiledName("Singleton")>]
        val inline singleton: value:'T -> 'T list

        /// <summary>Returns the list after removing the first N elements.</summary>
        /// <param name="count">The number of elements to skip.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The list after removing the first N elements.</returns>
        /// <exception cref="System.ArgumentException">Thrown when count is negative or exceeds the number of 
        /// elements in the list.</exception>
        [<CompiledName("Skip")>]
        val skip: count:int -> list: 'T list -> 'T list

        /// <summary>Bypasses elements in a list while the given predicate returns True, and then returns
        /// the remaining elements of the list.</summary>
        /// <param name="predicate">A function that evaluates an element of the list to a boolean value.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The result list.</returns>
        [<CompiledName("SkipWhile")>]
        val skipWhile: predicate:('T -> bool) -> list:'T list -> 'T list

        /// <summary>Sorts the given list using the given comparison function.</summary>
        ///
        /// <remarks>This is a stable sort, i.e. the original order of equal elements is preserved.</remarks>
        /// <param name="comparer">The function to compare the list elements.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The sorted list.</returns>
        [<CompiledName("SortWith")>]
        val sortWith: comparer:('T -> 'T -> int) -> list:'T list -> 'T list 

        /// <summary>Sorts the given list using keys given by the given projection. Keys are compared using Operators.compare.</summary>
        ///
        /// <remarks>This is a stable sort, i.e. the original order of equal elements is preserved.</remarks>
        /// <param name="projection">The function to transform the list elements into the type to be compared.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The sorted list.</returns>
        [<CompiledName("SortBy")>]
        val sortBy: projection:('T -> 'Key) -> list:'T list -> 'T list when 'Key : comparison

        /// <summary>Sorts the given list using Operators.compare.</summary>
        ///
        /// <remarks>This is a stable sort, i.e. the original order of equal elements is preserved.</remarks>
        /// <param name="list">The input list.</param>
        /// <returns>The sorted list.</returns>
        [<CompiledName("Sort")>]
        val sort: list:'T list -> 'T list when 'T : comparison

        /// <summary>Splits a list into two lists, at the given index.</summary>
        /// <param name="index">The index at which the list is split.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The two split lists.</returns>
        ///
        /// <exception cref="System.InvalidOperationException">Thrown when split index exceeds the number of elements
        /// in the list.</exception>
        [<CompiledName("SplitAt")>]
        val splitAt: index:int -> list:'T list -> ('T list * 'T list)

        /// <summary>Sorts the given list in descending order using keys given by the given projection. Keys are compared using Operators.compare.</summary>
        ///
        /// <remarks>This is a stable sort, i.e. the original order of equal elements is preserved.</remarks>
        /// <param name="projection">The function to transform the list elements into the type to be compared.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The sorted list.</returns>
        [<CompiledName("SortByDescending")>]
        val inline sortByDescending: projection:('T -> 'Key) -> list:'T list -> 'T list when 'Key : comparison

        /// <summary>Sorts the given list in descending order using Operators.compare.</summary>
        ///
        /// <remarks>This is a stable sort, i.e. the original order of equal elements is preserved.</remarks>
        /// <param name="list">The input list.</param>
        /// <returns>The sorted list.</returns>
        [<CompiledName("SortDescending")>]
        val inline sortDescending: list:'T list -> 'T list when 'T : comparison

        /// <summary>Returns the sum of the elements in the list.</summary>
        /// <param name="list">The input list.</param>
        /// <returns>The resulting sum.</returns>
        [<CompiledName("Sum")>]
        val inline sum   : list:^T list -> ^T 
                                   when ^T : (static member ( + ) : ^T * ^T -> ^T) 
                                   and  ^T : (static member Zero : ^T)

        /// <summary>Returns the sum of the results generated by applying the function to each element of the list.</summary>
        /// <param name="projection">The function to transform the list elements into the type to be summed.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The resulting sum.</returns>
        [<CompiledName("SumBy")>]
        val inline sumBy : projection:('T -> ^U) -> list:'T list -> ^U 
                                   when ^U : (static member ( + ) : ^U * ^U -> ^U) 
                                   and  ^U : (static member Zero : ^U)

        /// <summary>Returns the list after removing the first element.</summary>
        ///
        /// <param name="list">The input list.</param>
        /// <exception cref="System.ArgumentException">Thrown when the list is empty.</exception>
        /// <returns>The list after removing the first element.</returns>
        [<CompiledName("Tail")>]
        val tail: list:'T list -> 'T list

        /// <summary>Returns the first N elements of the list.</summary>
        /// <remarks>Throws <c>InvalidOperationException</c>
        /// if the count exceeds the number of elements in the list. <c>List.truncate</c>
        /// returns as many items as the list contains instead of throwing an exception.</remarks>
        ///
        /// <param name="count">The number of items to take.</param>
        /// <param name="list">The input list.</param>
        ///
        /// <returns>The result list.</returns>
        ///
        /// <exception cref="System.ArgumentException">Thrown when the input list is empty.</exception>
        /// <exception cref="System.InvalidOperationException">Thrown when count exceeds the number of elements
        /// in the list.</exception>
        [<CompiledName("Take")>]
        val take: count:int -> list:'T list -> 'T list

        /// <summary>Returns a list that contains all elements of the original list while the 
        /// given predicate returns True, and then returns no further elements.</summary>
        ///
        /// <param name="predicate">A function that evaluates to false when no more items should be returned.</param>
        /// <param name="list">The input list.</param>
        ///
        /// <returns>The result list.</returns>
        [<CompiledName("TakeWhile")>]
        val takeWhile: predicate:('T -> bool) -> list:'T list -> 'T list

        /// <summary>Builds an array from the given list.</summary>
        /// <param name="list">The input list.</param>
        /// <returns>The array containing the elements of the list.</returns>
        [<CompiledName("ToArray")>]
        val toArray: list:'T list -> 'T[]

        /// <summary>Views the given list as a sequence.</summary>
        /// <param name="list">The input list.</param>
        /// <returns>The sequence of elements in the list.</returns>
        [<CompiledName("ToSeq")>]
        val toSeq: list:'T list -> seq<'T>

        /// <summary>Returns the first element of the list, or
        /// <c>None</c> if the list is empty.</summary>
        /// <param name="list">The input list.</param>
        /// <returns>The first element of the list or None.</returns>
        [<CompiledName("TryHead")>]
        val tryHead: list:'T list -> 'T option

        /// <summary>Returns at most N elements in a new list.</summary>
        /// <param name="count">The maximum number of items to return.</param>
        /// <param name="array">The input list.</param>
        /// <returns>The result list.</returns>
        [<CompiledName("Truncate")>]
        val truncate: count:int -> list:'T list -> 'T list

        /// <summary>Applies the given function to successive elements, returning <c>Some(x)</c> the first
        /// result where function returns <c>Some(x)</c> for some x. If no such element 
        /// exists then return <c>None</c>.</summary>
        /// <param name="chooser">The function to generate options from the elements.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The first resulting value or None.</returns>
        [<CompiledName("TryPick")>]
        val tryPick: chooser:('T -> 'U option) -> list:'T list -> 'U option

        /// <summary>Returns the first element for which the given function returns True.
        /// Return None if no such element exists.</summary>
        /// <param name="predicate">The function to test the input elements.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The first element for which the predicate returns true, or None if
        /// every element evaluates to false.</returns>
        [<CompiledName("TryFind")>]
        val tryFind: predicate:('T -> bool) -> list:'T list -> 'T option

        /// <summary>Returns the last element for which the given function returns True.
        /// Return None if no such element exists.</summary>
        /// <param name="predicate">The function to test the input elements.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The last element for which the predicate returns true, or None if
        /// every element evaluates to false.</returns>
        [<CompiledName("TryFindBack")>]
        val tryFindBack: predicate:('T -> bool) -> list:'T list -> 'T option

        /// <summary>Returns the index of the first element in the list
        /// that satisfies the given predicate.
        /// Return <c>None</c> if no such element exists.</summary>
        /// <param name="predicate">The function to test the input elements.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The index of the first element for which the predicate returns true, or None if
        /// every element evaluates to false.</returns>
        [<CompiledName("TryFindIndex")>]
        val tryFindIndex: predicate:('T -> bool) -> list:'T list -> int option

        /// <summary>Tries to find the nth element in the list.
        /// Returns <c>None</c> if index is negative or the list does not contain enough elements.</summary>
        /// <param name="index">The index to retrieve.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The value at the given index or <c>None</c>.</returns>
        [<CompiledName("TryItem")>]
        val tryItem: index:int -> list:'T list -> 'T option

        /// <summary>Returns the index of the last element in the list
        /// that satisfies the given predicate.
        /// Return <c>None</c> if no such element exists.</summary>
        /// <param name="predicate">The function to test the input elements.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The index of the last element for which the predicate returns true, or None if
        /// every element evaluates to false.</returns>
        [<CompiledName("TryFindIndexBack")>]
        val tryFindIndexBack: predicate:('T -> bool) -> list:'T list -> int option

        /// <summary>Returns a list that contains the elements generated by the given computation.
        /// The given initial <c>state</c> argument is passed to the element generator.</summary>
        /// <param name="generator">A function that takes in the current state and returns an option tuple of the next
        /// element of the list and the next state value.</param>
        /// <param name="state">The initial state value.</param>
        /// <returns>The result list.</returns>
        [<CompiledName("Unfold")>]
        val unfold<'T,'State> : generator:('State -> ('T * 'State) option) -> state:'State -> 'T list

        /// <summary>Splits a list of pairs into two lists.</summary>
        /// <param name="list">The input list.</param>
        /// <returns>Two lists of split elements.</returns>
        [<CompiledName("Unzip")>]
        val unzip: list:('T1 * 'T2) list -> ('T1 list * 'T2 list)

        /// <summary>Splits a list of triples into three lists.</summary>
        /// <param name="list">The input list.</param>
        /// <returns>Three lists of split elements.</returns>
        [<CompiledName("Unzip3")>]
        val unzip3: list:('T1 * 'T2 * 'T3) list -> ('T1 list * 'T2 list * 'T3 list)
        
        /// <summary>Returns a new list containing only the elements of the list
        /// for which the given predicate returns "true"</summary>
        /// <param name="predicate">The function to test the input elements.</param>
        /// <param name="list">The input list.</param>
        /// <returns>A list containing only the elements that satisfy the predicate.</returns>
        [<CompiledName("Where")>]
        val where: predicate:('T -> bool) -> list:'T list -> 'T list

        /// <summary>Returns a list of sliding windows containing elements drawn from the input
        /// list. Each window is returned as a fresh list.</summary>
        /// <param name="windowSize">The number of elements in each window.</param>
        /// <param name="list">The input list.</param>
        /// <returns>The result list.</returns>
        /// <exception cref="System.ArgumentException">Thrown when windowSize is not positive.</exception>
        [<CompiledName("Windowed")>]
        val windowed : windowSize:int -> list:'T list -> 'T list list

        /// <summary>Combines the two lists into a list of pairs. The two lists must have equal lengths.</summary>
        /// <param name="list1">The first input list.</param>
        /// <param name="list2">The second input list.</param>
        /// <returns>A single list containing pairs of matching elements from the input lists.</returns>
        [<CompiledName("Zip")>]
        val zip: list1:'T1 list -> list2:'T2 list -> ('T1 * 'T2) list

        /// <summary>Combines the three lists into a list of triples. The lists must have equal lengths.</summary>
        /// <param name="list1">The first input list.</param>
        /// <param name="list2">The second input list.</param>
        /// <param name="list3">The third input list.</param>
        /// <returns>A single list containing triples of matching elements from the input lists.</returns>
        [<CompiledName("Zip3")>]
        val zip3: list1:'T1 list -> list2:'T2 list -> list3:'T3 list -> ('T1 * 'T2 * 'T3) list
